#include "mat_gamerule.h"
#include "mat_logicboard.h"
#include "mat_animation_mgr.h"
#include "mat_animation.h"
#include "mat_game.h"
#include "mat_tutorial.h"
#include "mat_ui_popupanimator.h"
#include "mat_ui_achievement_gain.h"
#include "mat_ui_gameover.h"
#include "mat_scoring.h"
#include "mat_level_manager.h"
#include "mat_sfx_manager.h"
#include "gen_game_state.h"
#include "mat_game.h"

#include "gameflow/game_flow_manager.h"
#include "nextpeer/np_manager.h"
#include "application/game_application.h"
#include "application/game_rms.h"
#include "num/rand.h"

#include <algorithm>


MATGameRule::MATGameRule() : m_CurrentTurn(0),
							 m_pTutorial(NULL),
							 m_Count_X(9),
							 m_Count_Y(9)
{
	//SetCountOfExcludeGemTypes(0);
	SetBoardCountXY(9,9);
    
	//MATLogicBoard::Instance().Clear();

	if( g_pApp && g_pApp->GetRMS() &&  
		g_pApp->GetRMS()->GetInt(RMS_TUTORIAL) <= TUTORIAL_LAST )	
		m_pTutorial = new MATTutorial();
}

MATGameRule::~MATGameRule()
{
	UTIL_SAFE_DELETE(m_pTutorial);
}


MATGameRule& MATGameRule::Instance()
{
	static MATGameRule inst;
	return inst;
}

void	MATGameRule::Tick(float dt)
{
	if(m_pTutorial)
	{
		if(m_pTutorial->IsFinish())
		{
			UTIL_SAFE_DELETE(m_pTutorial);
			NextTurn();
		}
	}
}

bool	MATGameRule::IsTutorialActive() const 
{ 
	// FIX THIS HARDCOE
	// for now I need to fix this bug with this ugly code
	if(MATLevelManager::Instance().GetCurrentLevel() >= 3 && MATLevelManager::Instance().GetCurrentLevel() <= 5 )
	{
		return false;
	}

	if(m_pTutorial && MATLevelManager::Instance().GetCurrentLevel() < TUTORIAL_LAST + 1)
	{
		return m_pTutorial->IsActive();
	}
	return false;
	
};

void	MATGameRule::NewGame()
{
    NextPeerManager::Instance().LaunchDashboard();
    
	GENGameState::GetGame()->GetGameMatch5()->AnimateShowBoard(0);
	MATScoring::Instance().NewGame();
	//RandomSpawnGemTypes();
	
	
	if(m_pTutorial)
	{
		m_pTutorial->Load();
		if(m_pTutorial->Start())
			return;
		//m_pTutorial->ForceFinish();
		//UTIL_SAFE_DELETE(m_pTutorial);
		//m_pTutorial = NULL;
		
	}

	

	MATGem* pGem;
	// add three small 
	int Count = 0;
	while(Count < 6 && MATLogicBoard::Instance().IsFull() == false)
	{
		int x = num::RAND32::Instance().RandInt(0,8);
		int y = num::RAND32::Instance().RandInt(0,8);
		pGem = MATLogicBoard::Instance().GetContentAt(y,x);

		if(
			( pGem == NULL || pGem->m_Type == 0)
			&&
			MATLogicBoard::Instance().GetTileAt(y,x) != TILE_UNREACHABLE &&
			MATLogicBoard::Instance().GetTileAt(y,x) != TILE_UNREACHABLE2
			)
		{
			MATGem* BC = GetNewGemToSpawn();
			MATLogicBoard::Instance().SetContentAt(y,x, BC );
			Count ++;
		}
	}
	
	NextTurn();
	m_CurrentTurn = 0;

	if(g_pApp && g_pApp->GetRMS())
		g_pApp->GetRMS()->Save();

}


void	MATGameRule::Start()
{
	//if(m_pTutorial)
	//{
	//	m_pTutorial->Start();
	//	return;
	//}
	
	//NewGame();	
	
}

	
void	MATGameRule::NextTurn()
{
	MATAnimation* pAni = NULL;		
	
	MATGem* BC;
	
	for(int y = 0; y< m_Count_Y; y++)
	{		
		for(int x = 0; x < m_Count_X; x++)
		{
			BC = MATLogicBoard::Instance().GetContentAt(y,x);
			
			// make small to big
			if(BC && BC->m_Type > 0 && BC->m_IsSmall )
			{
				BC->m_IsSmall = false;
				pAni = MATAnimationManager::Instance().AddAnimation(	
																y, 
																x, 
																BC,
																MATAnimation::ANI_TYPE_SMALLTOBIG
																);
				BC->m_IsSmall = true;	// right now, we have to wait for the animation.
				((MATAniSmallTobig*)pAni)->SetToMakeLogicallyBig(true);
				BC->m_IsSmall = true;	// right now, we have to wait for the animation.
			}

            // reduce bomb turns
			if(BC && BC->m_IsBomb && BC->m_IsSmall == false)
			{
				BC->m_BombTurnToExplode--;

				if(BC->m_BombTurnToExplode < 0)
				{
					// game should end and show lose screen.
					//BC->m_BombTurnToExplode = 0;
					MATLevelManager::Instance().SetState(MATLevelManager::STATE_BOMBEXPLODE);
					MATSFXManager::Instance().Spawn(MATSfx::SFX_BOMB_EXPLODE,MATGame::GetBoardPos(y,x),1.0f,0,false,MATSounds::SFX_EXPLODE_BOMB);
					MATLogicBoard::Instance().SetContentAt(y,x,NULL);

					if( MATLogicBoard::Instance().GetTileAt(y,x) == TILE_UNMOVEABLEGEM || MATLogicBoard::Instance().GetTileAt(y,x) == TILE_UNMOVEABLEGEM2)
					{
						MATSFXManager::Instance().Spawn(MATSfx::SFX_TILEUNMOVEABLE_EXPLODE,MATGame::GetBoardPos(y,x),1.0f,0,false,MATSounds::SFX_EXPLODE_TRAP);

						if(MATLogicBoard::Instance().GetTileAt(y,x) == TILE_UNMOVEABLEGEM )
							MATLogicBoard::Instance().ChangeTile( y,x ,TILE_NORMAL);
						else if(MATLogicBoard::Instance().GetTileAt(y,x) == TILE_UNMOVEABLEGEM2)
							MATLogicBoard::Instance().ChangeTile( y,x ,TILE_HARD); 
						else
							MATLogicBoard::Instance().ChangeTile( y,x , TILE_TYPE((int)MATLogicBoard::Instance().GetTileAt(y,x) - 1) );  	
					}
				}
			}
		}


	}
	

	if(m_pTutorial && IsTutorialActive())
	{
		m_pTutorial->AddSmallThree();
	}
	else if(MATLevelManager::Instance().IsPlaying())
	{
		MATGem* pGem;
		// add three small 
		int Count = 0;		
		while(Count < 3 && MATLogicBoard::Instance().IsFull() == false)
		{
			int x = num::RAND32::Instance().RandInt(0,8);
			int y = num::RAND32::Instance().RandInt(0,8);
			pGem = MATLogicBoard::Instance().GetContentAt(y,x);
			if( (pGem == false || pGem->m_Type == 0) &&
				MATLogicBoard::Instance().GetTileAt(y,x) != TILE_UNREACHABLE && 
				MATLogicBoard::Instance().GetTileAt(y,x) != TILE_UNREACHABLE2
				
				)
				
			{

				MATGem* BC = GetNewGemToSpawn();
				BC->m_IsSmall = true;
				MATLogicBoard::Instance().SetContentAt(y,x, BC);

				pAni = MATAnimationManager::Instance().AddAnimation(	y, 
																		x, 
																		BC,
																		MATAnimation::ANI_TYPE_SMALLTOBIG
																		);			
				BC->m_IsSmall = true;

				Count ++;
			}
		}
		if(pAni)
			pAni->SetCallBack(this);

		
	}

	MATUIAchievementGain* pAchievmentGain;
	pAchievmentGain = (MATUIAchievementGain*)MATUIPopupAnimatorMgr::Instance().GetPopup(MATUIPopupAnimatorMgr::POPUP_NAMES_ACHIEVEMENTGAIN);
	m_CurrentTurn++;

	if(m_CurrentTurn == 100)
		pAchievmentGain->GainAchievement(RMS_ACH_TURN100);		
	else if(m_CurrentTurn == 80)
		pAchievmentGain->GainAchievement(RMS_ACH_TURN80);
	else if(m_CurrentTurn == 2)
		pAchievmentGain->GainAchievement(RMS_ACH_TURN60);

	
	
}



void	MATGameRule::OnAnimationFinish(enum MATAnimation::ANI_TYPE AnimationType)
{
	
	//if(m_pTutorial)
	//	m_pTutorial->OnAnimationFinish(AnimationType);

	bool Matched = MATLogicBoard::Instance().CheckMatch5();	
	if(!Matched)
	{
		if(MATLogicBoard::Instance().IsAllBig() )
		{
			MATUIPopupAnimator* pPopup = MATUIPopupAnimatorMgr::Instance().Show(MATUIPopupAnimatorMgr::POPUP_NAMES_GAMEOVER);			
		}
		else if( MATLogicBoard::Instance().IsFull() )
		{
			NextTurn();
		}
		else if( MATLogicBoard::Instance().GetGemCount() < 6 )
		{
			NextTurn();
		}
	}
	else
	{
		MATLevelManager::Instance().CheckLevelComplete();
	}
}

void	MATGameRule::SetCountOfExcludeGemTypes(int Count)
{
	if(IsTutorialActive())
	{
		for(int i = 3; i < GEM_UNIQUE_COUNT; i++)
			m_ExclueGemType.push_back(i+1);
	}
	else
	{
		m_ExclueGemCount = Count;
		RandomSpawnGemTypes();
	}
}

void	MATGameRule::RandomSpawnGemTypes()
{
	int RandValue;
	m_ExclueGemType.resize(0);
	
	while( (int)m_ExclueGemType.size() < m_ExclueGemCount)
	{
		RandValue = num::RAND32::Instance().RandInt(  1,GEM_UNIQUE_COUNT);
		if( std::find(m_ExclueGemType.begin(), m_ExclueGemType.end(), RandValue ) == m_ExclueGemType.end() )
			m_ExclueGemType.push_back(RandValue);
	}
}

MATGem*		MATGameRule::GetNewGemToSpawn()
{
	MATGem*	ReturnVal = NULL;	

	for(int i =0; i < (int)m_GemList.size(); i++)
	{
		if(m_GemList[i]->m_IsFinish)
		{
			ReturnVal = m_GemList[i];
			ReturnVal->Reset();			
			
			i = (int)m_GemList.size();
		}
	}

	if( !ReturnVal)
		ReturnVal = new MATGem();


	m_GemList.push_back(ReturnVal);
	int		Random;
	

	while(1)
	{
		Random  = num::RAND32::Instance().RandInt(  1,
													GEM_UNIQUE_COUNT);
		if( std::find(m_ExclueGemType.begin(), m_ExclueGemType.end(), Random ) == m_ExclueGemType.end() )
		{
			ReturnVal->m_Type = Random;
			ReturnVal->m_IsSmall = true;

			
			if( MATLevelManager::Instance().ShouldSpawnMoreBombs() && num::RAND32::Instance().RandInt(1,20) == 1)
			{
				ReturnVal->m_IsBomb = true;
				ReturnVal->m_BombTurnToExplode = 20;
			}

			if( MATLevelManager::Instance().ShoulSpawnTimeBonus() )
			{
				if(num::RAND32::Instance().RandInt(1,5) == 1)
					ReturnVal->m_IsTimeBonus = true;
			}
			return ReturnVal;
		}
		
	}

	
	return ReturnVal;
}

void	MATGameRule::MouseButtonDown(const math::Vec2& Pos, int Y, int X)
{
	if(m_pTutorial)
		m_pTutorial->MouseButtonDown(Pos,Y,X);
}
	
void	MATGameRule::MouseButtonReleased(const math::Vec2& Pos, int Y, int X)
{
	if(m_pTutorial)
		m_pTutorial->MouseButtonReleased(Pos,Y,X);
}


